#include<iostream>
#include<string>

#include<stdio.h>
#include <stdlib.h>
#include<sys/stat.h>
#include<functional>
#include<fstream>
#include<cstring>
#include<cerrno>
#include"logger.hpp"
namespace filehelper{


class Filehelper{
    public:
        Filehelper(const std::string& filename):_filename(filename){}

        static bool exists(const std::string& filename){
            struct stat st;
            return (stat(filename.c_str(),&st) == 0);
        }
        bool exists(){
            struct stat st;
            return (stat(_filename.c_str(),&st) == 0);
        }

        static size_t size(const std::string& filename){
            struct stat st;
            if(stat(filename.c_str(),&st) != 0){
                return 0;
            }
            return st.st_size;
        }
        size_t size(){
            struct stat st;
            if(stat(_filename.c_str(),&st) != 0){
                return 0;
            }
            return st.st_size;
        }

        bool read(std::string* body,size_t offset,size_t len){
            body->resize(len);
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if(!ifs.is_open()){
                LOG_ERROR("open read false...");
                return false;
            }
            ifs.seekg(offset);
            ifs.read(&(*body)[0],len);
            if(!ifs.good()){
                LOG_ERROR("read false...");
                return false;
            }
            ifs.close();
            return true;
        }

        bool read(std::string* body){
            size_t len = Filehelper::size();
            return Filehelper::read(body,0,len);
        }

        bool write(const std::string& body,size_t offset,size_t len){
            std::fstream fs(_filename,std::ios::binary | std::ios::in | std::ios::out);
            if(!fs.is_open()){
                LOG_ERROR("open write false...");
                return false;
            }
            fs.seekg(offset);
            fs.write(body.c_str(),len);
            if(!fs.good()){
                LOG_ERROR("write false...");
                return false;
            }
            return true;
        }

        bool write(const std::string& body){
            //  有bug 会覆写 
            return Filehelper::write(body,0,body.size());
        }
        bool createFile(){
            std::ofstream of(_filename,std::ios::binary | std::ios::out);
            if(!of.is_open()){
                LOG_ERROR("creatfile false + %s",_filename.c_str());
                return false;
            }
            of.close();

            return true;
        }

        bool removeFile(){
            return (::remove(_filename.c_str()) == 0);
        }

        static bool createDirectory(const std::string& path){
            // ./a/b    a/b/c
            const std::string sep = "/";

            size_t start = 0,end;
            while(start < path.size()){
                end = path.find('/',start);
                if(end == std::string::npos){
                    std::string subpath = path;
                    mkdir(subpath.c_str(),0775);
                    return true;
                }
                std::string subpath = path.substr(0,end);
                int ret = mkdir(subpath.c_str(),0775); 
                if(ret != 0 && errno != EEXIST){
                    //eexist !!! 一开始有一个./ 所以要忽略
                    LOG_ERROR("create %s Directory false... %s",path.c_str(),strerror(errno));
                    return false;
                }
                start = end + sep.size();
            }
            return true;
        }
        bool removeDirectory(){
            if(_filename == "/")    
                return false;
            std::string comd = "rm -rf" + _filename;
            return (system(comd.c_str()) != -1);
        }

        static std::string parentDirectory(const std::string& filename){
            size_t pos = filename.rfind('/');
            if(pos == std::string::npos){
                return "./";
            }
            std::string path = filename.substr(0,pos);
            return path;
        }

    private:
        std::string _filename;
};

}